import json
from channels.generic.websocket import AsyncWebsocketConsumer
from channels.db import database_sync_to_async
from utils.jwttool import jwtTool
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
channel_layer = get_channel_layer()

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        """建立WebSocket连接"""
        try:
            from .models import ChatRoom, ChatRoomMember
            from Login.models import User, ThirdPartyAccount
            import traceback
            self.user = await self.get_user_from_token()
            self.room_id = self.scope['url_route']['kwargs']['room_id']
            self.room_group_name = f'chat_{self.room_id}'
            print(f"[WS连接] user_id={getattr(self.user, 'id', None)}, room_id={self.room_id}")

            # 校验成员
            is_member = await self.is_room_member(self.room_id, self.user.id)
            print(f"[WS成员校验] user_id={getattr(self.user, 'id', None)}, room_id={self.room_id}, is_member={is_member}")
            if not is_member:
                print(f"[WS拒绝] user_id={getattr(self.user, 'id', None)} 不是房间 {self.room_id} 成员")
                await self.close()
                return

            # group_add
            await self.channel_layer.group_add(
                self.room_group_name,
                self.channel_name
            )
            print(f"[WS加入group] user_id={self.user.id}, group={self.room_group_name}, channel={self.channel_name}")

            await self.accept()
            # 连接成功消息
            await self.send(text_data=json.dumps({
                'type': 'connection_established',
                'message': '连接成功',
                'user_id': self.user.id,
                'room_id': self.room_id
            }))
            # 推送历史消息
            history_messages = await self.get_history_messages(self.room_id, limit=20)
            await self.send(text_data=json.dumps({
                'type': 'history_messages',
                'messages': history_messages
            }))
        except Exception as e:
            import traceback
            print(f"[WS连接异常] {e}\n{traceback.format_exc()}")
            await self.close()

    async def disconnect(self, close_code):
        """断开WebSocket连接"""
        # 离开聊天室组
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    async def receive(self, text_data):
        """接收WebSocket消息"""
        try:
            text_data_json = json.loads(text_data)
            message_type = text_data_json.get('type', 'chat_message')
            if message_type == 'ping':
                print(f"收到心跳包 from user {self.user.id}")
                await self.send(text_data=json.dumps({'type': 'pong'}))
                return
            
            if message_type == 'chat_message':
                await self.handle_chat_message(text_data_json)
            elif message_type == 'read_messages':
                await self.handle_read_messages(text_data_json)
            elif message_type == 'typing':
                await self.handle_typing(text_data_json)
                
        except json.JSONDecodeError:
            await self.send(text_data=json.dumps({
                'type': 'error',
                'message': '消息格式错误'
            }))

    async def handle_chat_message(self, data):
        """处理聊天消息"""
        from .models import ChatMessage
        content = data.get('content', '').strip()
        message_type = data.get('message_type', 'text')
        file_url = data.get('file_url', '')
        
        if not content and message_type == 'text':
            return
        
        # 保存消息到数据库
        message = await self.save_message(
            self.room_id, 
            self.user.id, 
            content, 
            message_type, 
            file_url
        )
        
        # 获取用户信息
        user_info = await self.get_user_info(self.user.id)
        sender_nickname = user_info.get('nickname') or user_info.get('username') or f'用户{self.user.id}'
        # 组装消息内容
        msg_payload = {
            'id': message.id,
            'content': message.content,
            'message_type': message.message_type,
            'file_url': message.file_url,
            'created_at': message.created_at.isoformat(),
            'sender': {
                'id': self.user.id,
                'username': user_info.get('username', ''),
                'nickname': sender_nickname,
                'avatar': user_info.get('avatar') or '/default-avatar.png'
            },
            'room_id': self.room_id  # 确保房间消息有 room_id
        }
        # 只广播到房间 group
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': msg_payload
            }
        )
        print(f"用户 {self.user.id} 在房间 {self.room_id} 发送消息，group_send 到 {self.room_group_name}")

    async def handle_read_messages(self, data):
        """处理消息已读状态"""
        from .models import MessageReadStatus
        message_ids = data.get('message_ids', [])
        if message_ids:
            await self.mark_messages_as_read(message_ids, self.user.id)
            
            # 通知其他用户消息已读
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    'type': 'messages_read',
                    'message': {
                        'user_id': self.user.id,
                        'message_ids': message_ids
                    }
                }
            )

    async def handle_typing(self, data):
        """处理正在输入状态"""
        is_typing = data.get('is_typing', False)
        
        # 发送正在输入状态到聊天室组
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'user_typing',
                'message': {
                    'user_id': self.user.id,
                    'is_typing': is_typing
                }
            }
        )

    async def chat_message(self, event):
        """发送聊天消息到WebSocket"""
        print(f"[chat_message handler] room_id={self.room_id}, user_id={self.user.id}, channel_name={self.channel_name}, 收到消息: {event['message']}")
        await self.send(text_data=json.dumps({
            'type': 'chat_message',
            'message': event['message']
        }))

    async def messages_read(self, event):
        """发送消息已读状态到WebSocket"""
        await self.send(text_data=json.dumps({
            'type': 'messages_read',
            'message': event['message']
        }))

    async def user_typing(self, event):
        """发送用户正在输入状态到WebSocket"""
        await self.send(text_data=json.dumps({
            'type': 'user_typing',
            'message': event['message']
        }))

    @database_sync_to_async
    def get_user_from_token(self):
        """从token获取用户信息"""
        from .models import User
        try:
            # 从查询参数或headers中获取token
            query_string = self.scope.get('query_string', b'').decode()
            token = None
            
            # 从查询参数中获取token
            if 'token=' in query_string:
                token = query_string.split('token=')[1].split('&')[0]
            
            # 从headers中获取token
            if not token:
                headers = dict(self.scope['headers'])
                auth_header = headers.get(b'authorization', b'').decode()
                if auth_header.startswith('Bearer '):
                    token = auth_header[7:]
            
            if token:
                from utils.jwttool import jwtTool
                payload = jwtTool.checktoken(token)
                user_id = payload.get('userid')
                return User.objects.get(id=user_id)
        except Exception as e:
            print(f"获取用户信息失败: {e}")
            return None

    @database_sync_to_async
    def is_room_member(self, room_id, user_id):
        """检查用户是否为聊天室成员"""
        from .models import ChatRoomMember
        try:
            return ChatRoomMember.objects.filter(
                room_id=room_id, 
                user_id=user_id
            ).exists()
        except Exception:
            return False

    @database_sync_to_async
    def save_message(self, room_id, user_id, content, message_type, file_url):
        """保存消息到数据库"""
        from .models import ChatMessage
        return ChatMessage.objects.create(
            room_id=room_id,
            sender_id=user_id,
            content=content,
            message_type=message_type,
            file_url=file_url
        )

    @database_sync_to_async
    def get_user_info(self, user_id):
        """获取用户信息"""
        from .models import User
        from Login.models import ThirdPartyAccount
        try:
            user = User.objects.get(id=user_id)
            # 尝试获取第三方账号信息
            try:
                third_party = ThirdPartyAccount.objects.get(user=user, provider='dingtalk')
                return {
                    'username': user.phone,  # 只用 phone 字段
                    'nickname': third_party.nickname or user.phone,
                    'avatar': third_party.avatar_url or ''
                }
            except ThirdPartyAccount.DoesNotExist:
                return {
                    'username': user.phone,
                    'nickname': user.phone,
                    'avatar': ''
                }
        except User.DoesNotExist:
            return {
                'username': '',
                'nickname': '',
                'avatar': ''
            }

    @database_sync_to_async
    def mark_messages_as_read(self, message_ids, user_id):
        """标记消息为已读"""
        from .models import MessageReadStatus
        for message_id in message_ids:
            MessageReadStatus.objects.get_or_create(
                message_id=message_id,
                user_id=user_id
            ) 

    @database_sync_to_async
    def get_history_messages(self, room_id, limit=20):
        from .models import ChatMessage
        from Login.models import User, ThirdPartyAccount
        messages = ChatMessage.objects.filter(room_id=room_id).order_by('-created_at')[:limit]
        result = []
        for msg in reversed(messages):  # 正序
            sender = msg.sender
            # 获取第三方信息
            try:
                third_party = ThirdPartyAccount.objects.get(user=sender, provider='dingtalk')
                nickname = third_party.nickname or sender.phone
                avatar = third_party.avatar_url or ''
            except ThirdPartyAccount.DoesNotExist:
                nickname = sender.phone
                avatar = ''
            result.append({
                'id': msg.id,
                'content': msg.content,
                'message_type': msg.message_type,
                'file_url': msg.file_url,
                'created_at': msg.created_at.isoformat(),
                'sender': {
                    'id': sender.id,
                    'username': sender.phone,
                    'nickname': nickname,
                    'avatar': avatar
                },
                'room_id': room_id
            })
        return result

class GlobalConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        try:
            await self.channel_layer.group_add("global", self.channel_name)
            await self.accept()
            print(f"GlobalConsumer: {self.channel_name} joined global group")
        except Exception as e:
            print("GlobalConsumer connect error:", e)
            await self.close()

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard("global", self.channel_name)
        print(f"GlobalConsumer: {self.channel_name} left global group")

    async def receive(self, text_data):
        # 可选：可以处理客户端发来的消息，这里暂不处理
        pass

    async def global_message(self, event):
        print("GlobalConsumer 收到 global group 消息", event)
        await self.send(text_data=json.dumps({
            'type': 'global_message',
            'message': event.get('message', {})
        })) 

    async def chat_message(self, event):
        message = event.get('message', {})
        content = message.get('content', '')
        # 流式推送内容
        import asyncio
        for char in content:
            await self.send(text_data=json.dumps({
                'type': 'stream',
                'content': char,
                'message': message  # 可选：带上原始消息结构
            }))
            await asyncio.sleep(0.2)  # 明显拉慢流速，便于前端感知流动
        await self.send(text_data=json.dumps({'type': 'stream_end'})) 